package com.ruoyi.framework.security.jsonlogin;

import cn.hutool.core.lang.Assert;
import com.ruoyi.framework.web.service.SysLoginService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Setter
@Slf4j
public class JsonLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H, JsonLoginConfigurer<H>, JsonLoginUsernamePasswordAuthenticationFilter> {

    private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;

    private AuthenticationSuccessHandler successHandler;

    private AuthenticationFailureHandler failureHandler;

    private SysLoginService sysLoginService;

    public JsonLoginConfigurer() {
        super(new JsonLoginUsernamePasswordAuthenticationFilter(), null);
    }

    public JsonLoginConfigurer(JsonLoginUsernamePasswordAuthenticationFilter authenticationFilter, String defaultLoginProcessingUrl) {
        super(authenticationFilter, defaultLoginProcessingUrl);
    }

    public static JsonLoginConfigurer<HttpSecurity> jsonLogin(Customizer<JsonLoginConfigurer<HttpSecurity>> JsonLoginConfigurerCustomizer) {
        JsonLoginConfigurer<HttpSecurity> httpSecurityJsonLoginConfigurer = new JsonLoginConfigurer<>();
        JsonLoginConfigurerCustomizer.customize(httpSecurityJsonLoginConfigurer);
        return httpSecurityJsonLoginConfigurer;
    }

    @Override
    public JsonLoginConfigurer<H> securityContextRepository(SecurityContextRepository securityContextRepository) {
        return super.securityContextRepository(securityContextRepository);
    }

    @Override
    public void init(H http) throws Exception {
        Assert.notNull(sysLoginService, "sysLoginService is must not be null");
        super.init(http);
    }

    @Override
    public void configure(H http) {
        JsonLoginUsernamePasswordAuthenticationFilter authenticationFilter = getAuthenticationFilter();
        authenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
        authenticationFilter.setAuthenticationSuccessHandler(successHandler);
        authenticationFilter.setAuthenticationFailureHandler(failureHandler);
        authenticationFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
        authenticationFilter.setSysLoginService(sysLoginService);
        Optional.ofNullable(http.getSharedObject(SessionAuthenticationStrategy.class))
                .ifPresent(authenticationFilter::setSessionAuthenticationStrategy);
        Optional.ofNullable(http.getSharedObject(RememberMeServices.class))
                .ifPresent(authenticationFilter::setRememberMeServices);
        Filter filter = postProcess(authenticationFilter);
        http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected <T> T postProcess(T object) {
        return super.postProcess(object);
    }

    /**
     * 设置登录接口地址
     *
     * @param loginProcessingUrl the URL to validate username and password
     * @return this
     */
    @Override
    public JsonLoginConfigurer<H> loginProcessingUrl(String loginProcessingUrl) {
        return super.loginProcessingUrl(loginProcessingUrl);
    }

    /**
     * 设置需要拦截的登录接口地址
     *
     * @param loginProcessingUrl creates the {@link RequestMatcher} based upon the
     *                           loginProcessingUrl
     * @return RequestMatcher
     */
    @Override
    protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
        return new AntPathRequestMatcher(loginProcessingUrl, "POST");
    }


}
